#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>

#include "utils.h"
#include "aexgpio.h"
#include "mod_gpio.h"
#include "aexudp.h"
#include "version.h"
#include "kc031service.h"
#include "mqtt.h"
#include "sgw_device.h"

#ifdef USE_AEX_UDP

#include "sm4.h"

//AEX通用UDP通讯协议的解析处理函数
// static int aexudp_cmd_parse(unsigned char *buf,int len);
//AEX通用UDP通讯协议解析处理函数，DATA区数据为SM4加密数据，需要解码后使用
static int aexudp_cmd_parse_encrypt(unsigned char *data,int len);
static void aexudp_encrypt_soft_packnet(unsigned char *buf,int len);

PKTPROPO g_pktpropo[] = {
	{0xFB,0xFE,aexudp_cmd_parse,NULL},
	{0xEB,0xEE,aexudp_cmd_parse_encrypt,aexudp_encrypt_soft_packnet},
	{0,0,NULL},
};


int sgw_device_has_net(unsigned char modaddr)
{
    unsigned char slot = (modaddr>>4) & 0x0F;
    unsigned char type = (modaddr&0x0F)|0x10;
    int ret = 0;
    switch(slot){
    case 1:
    case 2:
    case 11:
    case 12:
        ret = 0;
        break;
    default:
        ret = 1;
        break;
    }
    switch(type){
    case SGW_TYPE_BS:
    case SGW_TYPE_NETSWITCH:
    case SGW_TYPE_UPS:
    case SGW_TYPE_ACDC:
    case SGW_TYPE_4G:
    case SGW_TYPE_AIO_BS:
    case SGW_TYPE_AI:
    case SGW_TYPE_AO:
        ret &= 0;
        break;
    default:
        ret &= 1;
    }
    return ret;
}

/**
 * 根据数据包获取
 */
PPKTPROPO aexudp_get_pktpropo(unsigned char *buf)
{
	unsigned char index = 0;
	PPKTPROPO pktpropo = &g_pktpropo[index];

	while (pktpropo->start != 0 && pktpropo->end != 0)
	{
		if(pktpropo->start == AEXUDP_GET_BEGIN(buf) && pktpropo->end == AEXUDP_GET_END(buf)){
			return pktpropo;
		}else{
			pktpropo = &g_pktpropo[++index];
		}
	}
	
	return NULL;
}

PPKTPROPO aexudp_get_pktpropo_byflag(unsigned char start,unsigned char end)
{
	unsigned char index = 0;
	PPKTPROPO pktpropo = &g_pktpropo[index];

	// psus_hint("%s:0x%02X,0x%02X\n",__func__,start,end);
	while (pktpropo->start != 0 && pktpropo->end != 0)
	{
		// psus_hint("%s[]:0x%02X,0x%02X\n",__func__,pktpropo->start,pktpropo->end);
		if(pktpropo->start == start && pktpropo->end == end){
			return pktpropo;
		}else{
			pktpropo = &g_pktpropo[++index];
		}
	}
	
	return NULL;
}

/**
 * 查找接收缓冲区的起始字符是否为能够识别的协议起始字符
 */
int aexudp_find_begin(unsigned char *buf)
{
	unsigned char index = 0;
	PPKTPROPO pktpropo = &g_pktpropo[index];

	while ( (pktpropo!=NULL) && pktpropo->start != 0 && pktpropo->end != 0)
	{
		if(pktpropo->start == AEXUDP_GET_BEGIN(buf)){
			return 1;
		}else{
			pktpropo = &g_pktpropo[++index];
		}
	}
	
	return 0;
}

/**
 * 查找
 */
int aexudp_check_pktpropo(unsigned char *buf)
{
	unsigned char index = 0;
	PPKTPROPO pktpropo = &g_pktpropo[index];

	while (pktpropo->start != 0 && pktpropo->end != 0)
	{
		if(pktpropo->start == AEXUDP_GET_BEGIN(buf) && pktpropo->end == AEXUDP_GET_END(buf)){
			return 1;
		}else{
			pktpropo = &g_pktpropo[++index];
		}
	}
	
	return 0;
}

int aexudp_sm4_encrypt(unsigned char *output,unsigned char *input,int len, unsigned char key[16])
{
	sm4_context ctx;
	unsigned long i;

	//encrypt standard testing vector
	sm4_setkey_enc(&ctx,key);
	sm4_crypt_ecb(&ctx,SM4_ENCRYPT,len,input,output);
}

int aexudp_sm4_dencrypt(unsigned char *output,unsigned char *input,int len, unsigned char key[16])
{
	sm4_context ctx;

	//decrypt testing
	sm4_setkey_dec(&ctx,key);
	sm4_crypt_ecb(&ctx,SM4_DECRYPT,len,input,output);
}

static unsigned char s_pindex=0;

unsigned char aexudp_get_packnet_index()
{
	if(s_pindex==0xFF)s_pindex=0;
	else s_pindex++;
	return s_pindex;
}

PPKTPROPO aexudp_get_default_prkpropo()
{
	psus_config *hcsdata = get_psus_data();
	return aexudp_get_pktpropo_byflag(AEXUDP_GETBEGIN(hcsdata->hcsdata.etype),AEXUDP_GETEND(hcsdata->hcsdata.etype));
}
/**
 * 不加密数据包编码函数，编码结果放入buf参数指定的缓冲区中
 */
void aexudp_encode_packnet(unsigned char *buf,unsigned char src,unsigned char dst,unsigned char cmd,unsigned char *data,unsigned char len)
// void aexudp_encode_packnet(unsigned char dst,unsigned char *buf,unsigned char cmd,unsigned char *data,unsigned char len)
{
	PPKTPROPO handle = aexudp_get_default_prkpropo();
	if(buf != NULL && handle != NULL){
		AEXUDP_SET_BEGIN(buf,handle->start);
		AEXUDP_SET_INDEX(buf,aexudp_get_packnet_index());
		AEXUDP_SET_LEN(buf,len+AEXUDP_DATA_GET_PAYLOADINDEX());
		AEXUDP_SET_CMD(buf,cmd);
		AEXUDP_DATA_SET_SRC(AEXUDP_GET_DATA(buf),src);
		AEXUDP_DATA_SET_DST(AEXUDP_GET_DATA(buf),dst);
		AEXUDP_DATA_SET_PAYLOAD(AEXUDP_GET_DATA(buf),data,len);
		if(handle->encrypt){
			handle->encrypt(buf,AEXUDP_GET_LEN(buf));
		}else{
			AEXUDP_SET_CRC(buf);
		}
		AEXUDP_SET_END(buf,handle->end);

	}
}

static void aexudp_encrypt_soft_packnet(unsigned char *buf,int len)
{
	psus_config *hcsdata = get_psus_data();
	unsigned char edata[255];

	memcpy(edata,0,sizeof(edata));

	aexudp_sm4_encrypt(edata,AEXUDP_GET_DATA(buf),AEXUDP_GET_LEN(buf),hcsdata->hcsdata.ekey);
	AEXUDP_SET_DATA(buf,edata,AEXUDP_GET_LEN(buf));
	AEXUDP_SET_CRC(buf);
}

static void aexudp_encrypt_none_packnet(unsigned char *buf,int len)
{
}

/**
 * 构造设备心跳的数据包
 */
void aexudp_buid_heart_packnet()
{
	unsigned char buf[256];

	psus_hint("%s:%d",__func__,__LINE__);
	PPKTPROPO handle = aexudp_get_default_prkpropo();
	if(handle != NULL){
		unsigned char index=0;
		unsigned char *pdata = AEXUDP_DATA_GET_PAYLOAD(AEXUDP_GET_DATA(buf));
		unsigned int in = aexgpio_get_in();
		unsigned int out = aexgpio_get_out();

		memset(buf,0,sizeof(buf));
		AEXUDP_SET_BEGIN(buf,handle->start);
		AEXUDP_SET_INDEX(buf,aexudp_get_packnet_index());
		AEXUDP_SET_CMD(buf,AEX_CMD_HEART);
		AEXUDP_DATA_SET_SRC(AEXUDP_GET_DATA(buf),aexgpio_get_mod_addr());
		AEXUDP_DATA_SET_DST(AEXUDP_GET_DATA(buf),0);				//边缘计算的心跳是发给服务器的
		pdata[index++] = DEFAULT_GPIO_ADDR;					//设置开关量地址或者组序号，默认为0
		// psus_hint("HEART:DO index=%d",index);
		index = aexgpio_set_pdata_dio(pdata,index,NUM_AEXGPIO_OUT,aexgpio_get_out());
		// psus_hint("HEART:DI index=%d",index);
		index = aexgpio_set_pdata_dio(pdata,index,NUM_AEXGPIO_IN,aexgpio_get_in());
		// psus_hint("HEART:AO index=%d",index);
		index = aexgpio_set_pdata_ao(pdata[0],pdata,index,aexgpio_get_aonum(pdata[0]));
		// psus_hint("HEART:AI index=%d",index);
		index = aexgpio_set_pdata_ai(pdata[0],pdata,index,aexgpio_get_ainum(pdata[0]));
		// psus_hint("HEART:GIT index=%d",index);
		pdata[index++] = (APP_VERSION_NUM>>24)&0xFF;		//GIT版本号 
		pdata[index++] = (APP_VERSION_NUM>>16)&0xFF;		//GIT版本号 
		pdata[index++] = (APP_VERSION_NUM>>8)&0xFF;		//GIT版本号 
		pdata[index++] = (APP_VERSION_NUM)&0xFF;			//GIT版本号 
		memcpy(&pdata[index],APP_VERSION_STR,strlen(APP_VERSION_STR));
		index += strlen(APP_VERSION_STR)+1;
		AEXUDP_SET_LEN(buf,index+AEXUDP_DATA_GET_PAYLOADINDEX());
		if(handle->encrypt){
			handle->encrypt(buf,AEXUDP_GET_LEN(buf));
		}else{
			AEXUDP_SET_CRC(buf);
		}
		AEXUDP_SET_END(buf,handle->end);
	}
	SendtoServer(buf,AEXUDP_GET_PACKET_LEN(buf));
}

void aexudp_buid_status_packnet(unsigned char cmd)
{
	unsigned char buf[256];

	psus_hint("%s:%d",__func__,__LINE__);
	PPKTPROPO handle = aexudp_get_default_prkpropo();
	if(handle != NULL){
		unsigned char index=0;
		unsigned char *pdata = AEXUDP_DATA_GET_PAYLOAD(AEXUDP_GET_DATA(buf));
		unsigned int in = aexgpio_get_in();
		unsigned int out = aexgpio_get_out();

		memset(buf,0,sizeof(buf));
		AEXUDP_SET_BEGIN(buf,handle->start);
		AEXUDP_SET_INDEX(buf,aexudp_get_packnet_index());
		AEXUDP_SET_CMD(buf,cmd);
		AEXUDP_DATA_SET_SRC(AEXUDP_GET_DATA(buf),aexgpio_get_mod_addr());
		AEXUDP_DATA_SET_DST(AEXUDP_GET_DATA(buf),0);				//边缘计算的心跳是发给服务器的

		// psus_hint("STATUS:DO index=%d",index);
		index = aexgpio_set_pdata_dio(pdata,index,NUM_AEXGPIO_OUT,aexgpio_get_out());
		// psus_hint("STATUS:DI index=%d",index);
		index = aexgpio_set_pdata_dio(pdata,index,NUM_AEXGPIO_IN,aexgpio_get_in());
		// psus_hint("STATUS:AO index=%d",index);
		index = aexgpio_set_pdata_ao(pdata[0],pdata,index,aexgpio_get_aonum(pdata[0]));
		// psus_hint("STATUS:AI index=%d",index);
		index = aexgpio_set_pdata_ai(pdata[0],pdata,index,aexgpio_get_ainum(pdata[0]));
		// psus_hint("STATUS:GIT index=%d",index);
		pdata[index++] = (APP_VERSION_NUM>>24)&0xFF;		//GIT版本号 
		pdata[index++] = (APP_VERSION_NUM>>16)&0xFF;		//GIT版本号 
		pdata[index++] = (APP_VERSION_NUM>>8)&0xFF;		//GIT版本号 
		pdata[index++] = (APP_VERSION_NUM)&0xFF;			//GIT版本号 
		memcpy(&pdata[index],APP_VERSION_STR,strlen(APP_VERSION_STR));
		index += strlen(APP_VERSION_STR)+1;
		AEXUDP_SET_LEN(buf,index+AEXUDP_DATA_GET_PAYLOADINDEX());
		if(handle->encrypt){
			handle->encrypt(buf,AEXUDP_GET_LEN(buf));
		}else{
			AEXUDP_SET_CRC(buf);
		}
		AEXUDP_SET_END(buf,handle->end);
		SendtoServer(buf,AEXUDP_GET_PACKET_LEN(buf));
	}
}

/**
 * @brief 单发输入变化的数据包，一般情况下不会有绝对的输入同时发生，一般都是单发的
 * 
 * @param index 输入序号
 * @param level 高低电平
 */
void aexudp_oninput(int index,int level)
{
	char buf[250];

	psus_hint("%s:%d",__func__,__LINE__);
	PPKTPROPO handle = aexudp_get_default_prkpropo();
	if(handle != NULL){
		unsigned char index=0;
		unsigned char *pdata = AEXUDP_DATA_GET_PAYLOAD(AEXUDP_GET_DATA(buf));
		unsigned int in = aexgpio_get_in();
		unsigned int out = aexgpio_get_out();

		memset(buf,0,sizeof(buf));
		AEXUDP_SET_BEGIN(buf,handle->start);
		AEXUDP_SET_INDEX(buf,aexudp_get_packnet_index());
		AEXUDP_SET_CMD(buf,AEX_CMD_DIEVENT_ONE);
		AEXUDP_DATA_SET_SRC(AEXUDP_GET_DATA(buf),aexgpio_get_mod_addr());
		AEXUDP_DATA_SET_DST(AEXUDP_GET_DATA(buf),0);				//边缘计算的心跳是发给服务器的
		pdata[index++] = 0x00;						//GPIO 的地址或者分组序号
		pdata[index++] = index&0xFF;									//输入事件的序号
		pdata[index++] = level&0xFF;									//输入事件值，高低电平
		AEXUDP_SET_LEN(buf,index+2);
		if(handle->encrypt){
			handle->encrypt(buf,AEXUDP_GET_LEN(buf));
		}else{
			AEXUDP_SET_CRC(buf);
		}
		AEXUDP_SET_END(buf,handle->end);
		SendtoServer(buf,AEXUDP_GET_PACKET_LEN(buf));
	}
}

void aexudp_do_func_rsp(char *func,int ret)
{
	char buf[250];

	psus_hint("%s:%d",__func__,__LINE__);
	PPKTPROPO handle = aexudp_get_default_prkpropo();
	if(handle != NULL){
		unsigned char index=0;
		unsigned char *pdata = AEXUDP_DATA_GET_PAYLOAD(AEXUDP_GET_DATA(buf));
		unsigned int in = aexgpio_get_in();
		unsigned int out = aexgpio_get_out();

		memset(buf,0,sizeof(buf));
		AEXUDP_SET_BEGIN(buf,handle->start);
		AEXUDP_SET_INDEX(buf,aexudp_get_packnet_index());
		AEXUDP_SET_CMD(buf,AEX_CMD_DOLUAFUNC);
		AEXUDP_DATA_SET_SRC(AEXUDP_GET_DATA(buf),aexgpio_get_mod_addr());
		AEXUDP_DATA_SET_DST(AEXUDP_GET_DATA(buf),0);				//边缘计算的心跳是发给服务器的
		pdata[index++] = ret&0xFF;									//返回值
		memcpy(pdata,func,strlen(func));							//执行的函数
		index += strlen(func)+1;
		AEXUDP_SET_LEN(buf,index+2);
		if(handle->encrypt){
			handle->encrypt(buf,AEXUDP_GET_LEN(buf));
		}else{
			AEXUDP_SET_CRC(buf);
		}
		AEXUDP_SET_END(buf,handle->end);
		SendtoServer(buf,AEXUDP_GET_PACKET_LEN(buf));
	}
}

/**
 * @brief AEXUDP处理输入变化
 * 	可以处理同时多个输入的变化
 * @param value 
 * @param old 
 */
void aexudp_handle_uevent(int value,int old)
{
	int index;

	//需要判断value和old的每一位是否相同
	for(index = AEXIN_MIN_INDEX;index <= AEXIN_MAX_INDEX;index++){
		int mask = 1<<index;
		if((value&mask) != (old&mask)){
			aexudp_oninput(index, value&mask>0?1:0);
			psus_hint("oninput(%d,%d)\n",index,value&mask>0?1:0);
		}
	}
}

/*
btn :应该是板子上的输入口状态
*/
void aexudp_report_iostatus(unsigned char cmd)
{
	char buf[250];
	
	aexudp_buid_status_packnet(cmd);
}

void aexudp_report_cmd_ret(unsigned char cmd,int ret)
{
	char buf[250];

	psus_hint("%s:%d",__func__,__LINE__);
	PPKTPROPO handle = aexudp_get_default_prkpropo();
	if(handle != NULL){
		unsigned char index=0;
		unsigned char *pdata = AEXUDP_DATA_GET_PAYLOAD(AEXUDP_GET_DATA(buf));
		unsigned int in = aexgpio_get_in();
		unsigned int out = aexgpio_get_out();

		memset(buf,0,sizeof(buf));
		AEXUDP_SET_BEGIN(buf,handle->start);
		AEXUDP_SET_INDEX(buf,aexudp_get_packnet_index());
		AEXUDP_SET_CMD(buf,AEX_CMD_DIEVENT);
		AEXUDP_DATA_SET_SRC(AEXUDP_GET_DATA(buf),aexgpio_get_mod_addr());
		AEXUDP_DATA_SET_DST(AEXUDP_GET_DATA(buf),0);				//边缘计算的心跳是发给服务器的
		// psus_hint("STATUS:DO index=%d",index);
		index = aexgpio_set_pdata_dio(pdata,index,NUM_AEXGPIO_OUT,aexgpio_get_out());
		// psus_hint("STATUS:DI index=%d",index);
		index = aexgpio_set_pdata_dio(pdata,index,NUM_AEXGPIO_IN,aexgpio_get_in());
		// psus_hint("STATUS:AO index=%d",index);
		index = aexgpio_set_pdata_ao(pdata[0],pdata,index,aexgpio_get_aonum(pdata[0]));
		// psus_hint("STATUS:AI index=%d",index);
		index = aexgpio_set_pdata_ai(pdata[0],pdata,index,aexgpio_get_ainum(pdata[0]));
		// psus_hint("STATUS:GIT index=%d",index);
		pdata[index++] = (APP_VERSION_NUM>>24)&0xFF;		//GIT版本号 
		pdata[index++] = (APP_VERSION_NUM>>16)&0xFF;		//GIT版本号 
		pdata[index++] = (APP_VERSION_NUM>>8)&0xFF;		//GIT版本号 
		pdata[index++] = (APP_VERSION_NUM)&0xFF;			//GIT版本号 
		memcpy(&pdata[index],APP_VERSION_STR,strlen(APP_VERSION_STR));
		index += strlen(APP_VERSION_STR)+1;
		AEXUDP_SET_LEN(buf,index+AEXUDP_DATA_GET_PAYLOADINDEX());
		if(handle->encrypt){
			handle->encrypt(buf,AEXUDP_GET_LEN(buf));
		}else{
			AEXUDP_SET_CRC(buf);
		}
		AEXUDP_SET_END(buf,handle->end);
		SendtoServer(buf,AEXUDP_GET_PACKET_LEN(buf));
	}
}

/**
 * @brief 把任务计划中的不符合文件名规则的字符换成其他字符，合成一个文件名
 * 
 * @param fn 
 * @param timer_buf 
 * @param n 
 */
void aexudp_get_fn(char *fn,char *timer_buf[],int n)
{
	int i,j;
	int index=0;
	strcpy(fn,"timer");
	index += strlen(fn);
	for(i=0;i<n;i++){
		for(j=0;j<strlen(timer_buf[i]);j++){
			switch (timer_buf[i][j])
			{
			case '*':
				fn[index++] =  's';
				break;
			case '\\':
				fn[index++] =  'x';
				break;
			case '/':
				fn[index++] =  'b';
			case ' ':
				fn[index++] =  '-';
			case '?':
				fn[index++] =  'w';
			case '%':
				fn[index++] =  'p';
			case ',':
				fn[index++] =  'd';
			default:
				fn[index++] = timer_buf[i][j];
				break;
			}
		}
	}
}

/**
 * @brief 把与正则表达式冲突的字符加上转义符
 * 
 * @param regex 可用于搜索的正则表达式的字符串
 * @param timer_buf 
 * @param n 
 */
void aexudp_get_regex(char *regex,char *timer_buf[],int n)
{
	int i,j;
	int index=0;
	for(i=0;i<n;i++){
		for(j=0;j<strlen(timer_buf[i]);j++){
			switch (timer_buf[i][j])
			{
			case '*':
				regex[index++] =  '\\';
				regex[index++] =  '*';
				break;
			case '/':
				regex[index++] =  '\\';
				regex[index++] =  '/';
			case '+':
				regex[index++] =  '\\';
				regex[index++] =  '+';
			case '?':
				regex[index++] =  '\\';
				regex[index++] =  '?';
			case '%':
				regex[index++] =  '\\';
				regex[index++] =  '%';
			case '^':
				regex[index++] =  '\\';
				regex[index++] =  '^';
			default:
				regex[index++] = timer_buf[i][j];
				break;
			}
		}
		regex[index++] =  ' ';
	}
}

// void aexudp_cmd(unsigned char *buf,size_t len)
// {
// 	unsigned char *p = buf;

// 	//psus_hint("aexudp cmd : %02x", AEXUDP_GET_CMD(p));
// 	if(AEXUDP_GET_END(p) == AEXUDP_END) //&& AEXUDP_GET_CRC(p) == crc8(AEXUDP_GET_CRCDATA(buf),AEXUDP_GET_CRCLEN(buf)))
// 	{
// 		unsigned char *data=AEXUDP_GET_DATA(buf);
// 		switch (AEXUDP_GET_CMD(p))
// 		{
// 		case AEX_CMD_IOSTATUS:	//请求设备IO状态，向服务器报告IO状态，可以作为心跳上报的数据
// 			if(AEXUDP_GET_LEN(p)>=1){
// 				int ioaddr = data[0];
// 				//上报IO状态
// 				if(ioaddr == 0){
// 					aexudp_report_iostatus(AEX_CMD_IOSTATUS);
// 				}
// 			}
// 			break;
// 		case AEX_CMD_OUTSET:	//设置输出状态，可以单设，也可以批量设置，依据掩码实现
// 			if(AEXUDP_GET_LEN(p)>=5){
// 				int ioaddr = data[0];
// 				if(ioaddr == 0){
// 					unsigned short mask,value,delay=0,delay_s=0;

// 					value = (data[1]<<8) | data[2];
// 					mask = (data[3]<<8) | data[4];

// 					if(AEXUDP_GET_LEN(p)>=7){
// 						delay = (data[5]<<8) | data[6];
// 					}
// 					if(AEXUDP_GET_LEN(p)>=9){
// 						delay_s = (data[7]<<8) | data[8];
// 					}
// 					//psus_hint("cmd:%02X,v=%04X,m=%04X,d=%04X",AEX_CMD_OUTSET,value,mask,delay);
// 					if(delay > 0){
// 						if(fok_for_timer(delay,delay_s) == 0){
// 							//使用子进程延迟执行
// 							if(get_psus_data()->hasgpio){
// 								kc031_set_out(mask,value);
// 							}
// 							aexudp_report_iostatus(AEX_CMD_IOSTATUS);
// 							exit_for_fok();		//执行完延迟任务退出子进程
// 						}
// 					}else{
// 						//立即执行
// 						if(get_psus_data()->hasgpio){
// 							kc031_set_out(mask,value);
// 						}
// 						aexudp_report_iostatus(AEX_CMD_IOSTATUS);
// 					}
// 				}
// 			}
// 			break;
// 		case AEX_CMD_OUTINVERT:	//设置输出反转，可以单设，也可以批量设置，依据掩码实现
// 			if(AEXUDP_GET_LEN(p)>=3){
// 				int ioaddr = data[0];
// 				if(ioaddr == 0){
// 					unsigned short mask,delay=0,delay_s=0;

// 					mask = (data[1]<<8) | data[2];
// 					if(AEXUDP_GET_LEN(p)>=5){
// 						delay = (data[3]<<8) | data[4];
// 					}
// 					if(AEXUDP_GET_LEN(p)>=7){
// 						delay_s = (data[5]<<8) | data[6];
// 					}
// 					//psus_hint("=add:%02x==cmd:%02X,m=%04X,d=%04X===\n", ioaddr, AEX_CMD_OUTINVERT,mask,delay);
// 					if(delay > 0){
// 						if(fok_for_timer(delay,delay_s) == 0){
// 							//使用子进程延迟执行
// 							if(get_psus_data()->hasgpio){
// 								kc031_set_out_invert(mask);
// 							}
// 							aexudp_report_iostatus(AEX_CMD_IOSTATUS);
// 							exit_for_fok();		//执行完延迟任务退出子进程
// 						}
// 					}else{
// 						//立即执行
// 						if(get_psus_data()->hasgpio){
// 							kc031_set_out_invert(mask);
// 						}
// 						aexudp_report_iostatus(AEX_CMD_IOSTATUS);
// 					}
// 				}
// 			}
// 			break;
// 		case AEX_CMD_DELTIMER:	//删除定时任务
// 		case AEX_CMD_SETTIMER:	//设置定时任务，边云测控终端的定时任务使用Linux的crontab来实现。边云测控终端通过从服务器下载shell脚本到机器，然后设置crontab任务来执行此脚本。
// 			if(AEXUDP_GET_LEN(p)>=1){
// 				/*
// 				timer_buf[0]~~timer_buf[4]:分 时 天 月 星期几 
// 				timer_buf[5]：脚本文件名称：例如，脚本文件为startOut.sh,  那么timer_buf[5] = "startOut.sh"
// 				timer_buf[6]：脚本文件的启动参数

// 				curl 基于ftp协议的下载命令（需要服务器开启ftp服务）
// 				curl ftp://192.168.1.100:21/curl_test.sh > /etc/kc031srv/curl_test.sh

// 				*/
// 				char *timer_buf[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
// 				//#define URL_FTP "ftp://192.168.1.100:21/"	//测试使用

// 				//提供了脚本代码
// 				char cmdline[300];
// 				char regex[100];
// 				int ret = 0;
				
// 				if(fok_for_timer(MS_DELAY_FORK,0) == 0)
// 				{
// 					//psus_hint("nwe fork son");
// 					//使用子进程进行设置工作
// 					split_args_onbuffer(data,timer_buf,7,' ');
// 					memset(cmdline, 0, sizeof(cmdline));
// 					memset(regex, 0, sizeof(regex));
// 					aexudp_get_regex(regex, timer_buf, 5);
					
// 					if( timer_buf[5] == NULL){
// 						psus_error("No shell file name.");
// 						break;
// 					}else{
// 						sprintf(cmdline, "sed -i '/%s/,1 d' /etc/crontabs/root", regex); //删除任务计划
// 						psus_hint(cmdline);
// 						ret = system(cmdline);
// 						sprintf(cmdline, "rm /etc/kc031srv/%s", timer_buf[5]);
// 						psus_hint(cmdline);
// 						ret = system(cmdline);

// 						if( AEXUDP_GET_CMD(p) == AEX_CMD_SETTIMER )//新增任务
// 						{	
// 							if(timer_buf[6]){
// 								sprintf(cmdline,"curl %s/%s > /etc/kc031srv/%s", timer_buf[6], timer_buf[5]);
// 								psus_hint(cmdline);
// 								int ret = system(cmdline);
// 								sprintf(cmdline, "chmod +x /etc/kc031srv/%s", timer_buf[5]);
// 								psus_hint(cmdline);
// 								ret = system(cmdline);
// 								sprintf(cmdline, "sed '/%s/,1 d' /etc/crontabs/root", regex);
// 								psus_hint(cmdline);
// 								ret = system(cmdline);
// 								sprintf(cmdline, "echo \"%s %s %s %s %s /etc/kc031srv/%ss\n\" >> /etc/crontabs/root",
// 										timer_buf[0], timer_buf[1], timer_buf[2], timer_buf[3],
// 										timer_buf[4], timer_buf[5]);
// 								psus_hint(cmdline);
// 								ret = system(cmdline);
// 							}
// 						}
// 					}
// 					aexudp_report_cmd_ret(AEX_CMD_SETTIMER, ret);
// 					exit_for_fok(); //执行完延迟任务退出子进程
// 				}
// 			}
// 			break;
// 		case AEX_CMD_ONINPUT_LUA:
// 			if(AEXUDP_GET_LEN(p)>=1){
// 				if(strlen(data) == 0){
// 					psus_error("No lua file address.");
// 					break;
// 				}else{
// 					if(fok_for_timer(MS_DELAY_FORK,0) == 0){
// 						//使用子进程进行设置工作
// 						//提供了脚本代码
// 						char cmdline[300];
						
// 						memset(cmdline,0,sizeof(cmdline));
// 						sprintf(cmdline,"curl %s > /etc/kc031srv/oninput.lua",data);
// 						psus_hint(cmdline);
// 						int ret = system(cmdline);
// 						if(ret == 0){
// 							memset(cmdline,0,sizeof(cmdline));
// 							sprintf(cmdline,"chmod +x etc/kc031srv/oninput");
// 							psus_hint(cmdline);
// 							ret = system(cmdline);
// 						}
// 						aexudp_report_cmd_ret(AEX_CMD_SETTIMER,ret);
// 						exit_for_fok();		//执行完延迟任务退出子进程
// 					}
// 				}
// 			}
// 			break;
// 		case AEX_CMD_DOONINPUT:
// 			if(AEXUDP_GET_LEN(p)>1){
// 				int in = data[0];
// 				int level = data[1];
// 				#ifdef USE_LUA
// 					lua_exec_one(get_psus_data()->lua_fn,in,level);
// 				#endif
// 			}
// 			break;
// 		case AEX_CMD_DOINPUTCHANGE:		//从命令行获得输入变化的EVENT会发送此命令，从/etc/hotplug.d/aexgpio27/00-changed调用
// 			if(AEXUDP_GET_LEN(p) > 3){
// 				unsigned short v = (data[0]<<8)|data[1];
// 				unsigned short ov = (data[2]<<8)|data[3];

// 				#ifdef USE_LUA
// 					lua_exec(get_psus_data()->lua_fn,v,ov);
// 				#endif
// 			}
// 			break;
// 		case AEX_CMD_MQTT_TX:
// 			if(AEXUDP_GET_LEN(p)>1)
// 			{
// 				/*
// 				buffer[0],用于mqtt发送的消息内容
// 				buffer[1],如果有的话，用作mqtt发送的主题。如果没有的话就用默认的主题发送。
// 				*/
// 				char *buffer[2] = {NULL, NULL};
// 				split_args_onbuffer(data, buffer, 2, ' ');
// 				if (buffer[0] != NULL)
// 				{
// 					#ifdef USE_LUA
// 						if( buffer[1] != NULL )
// 						{
// 							mqtt_pub(buffer[0],strlen(buffer[0]));
// 							mqtt_pub(buffer[1], strlen(buffer[1]));
// 						}else{
//							mqtt_pub(buffer[0],strlen(buffer[0]));
// 						}
// 					#endif
// 				}
				
// 			}
// 			break;
// 		case AEX_CMD_UART_DATA:
// 			if(AEXUDP_GET_LEN(p)>0 && get_psus_data()->uart_fd){
// 				if(get_psus_data()->uartpassto == AEX_UART_RADARPACKET_TOTCP){
// 					write(get_psus_data()->uart_fd,data,AEXUDP_GET_LEN(buf));
// 				}else{
// 					kc031_rs485_write(get_psus_data()->uart_fd,data,AEXUDP_GET_LEN(buf));
// 				}
// 			}
// 			break;
// 		case AEX_CMD_DO_LUAFUNC:
// 			if(AEXUDP_GET_LEN(p) > 3){
// 				unsigned char p1 = data[0];						
// 				unsigned char p2 = data[1];					
// 				char *luafunc = &data[2];	

// 				data[AEXUDP_GET_LEN(p)-1] = '\0';	//函数名要自带结尾符，如果没有会强制加结尾，否则会导致函数名少一个字符
// 				#ifdef USE_LUA
// 					lua_exec_userfunc(get_psus_data()->lua_fn,luafunc,p1,p2);
// 				#endif
// 			}
// 			break;
// 		default:
// 			psus_error("Unknown aexudp command.");
// 			aexudp_report_iostatus(AEXUDP_GET_CMD(p));
// 			break;
// 		}
// 	}
// }

/**
 * 是否为回环包，由于RS485和UDP广播包的支持，会收到自己发出的数据包
 */
int aexudp_is_loopback(unsigned char *buf,int len)
{
	unsigned char *data = AEXUDP_GET_DATA(buf);
	unsigned char dst_addr = AEXUDP_DATA_GET_DST(data);		//接受命令的设备地址，0表示广播命令
	unsigned char src_addr = AEXUDP_DATA_GET_SRC(data);

	if((dst_addr == aexgpio_get_mod_addr()||is_gw_broadcast(dst_addr)) && src_addr == aexgpio_get_mod_addr()){
		//如果是发给自己的或者是发给
		return 1;
	}

	return 0;
}

int aexudp_cmd_parse(unsigned char *buf,int len)
{
	psus_config *hcsdata = get_psus_data();
	unsigned char *data = AEXUDP_GET_DATA(buf);
	unsigned char plen = AEXUDP_GET_LEN(buf)-AEXUDP_DATA_GET_PAYLOADINDEX();
	unsigned char *pdata = AEXUDP_DATA_GET_PAYLOAD(data);
	unsigned char dst_addr = AEXUDP_DATA_GET_DST(data);		//接受命令的设备地址，0表示广播命令
	unsigned char src_addr = AEXUDP_DATA_GET_SRC(data);

	if(1){
		char dphex[512];
		int dlen=sizeof(dphex);

		memset(dphex,0, dlen);
		// HexEncode(AEXUDP_DATA_GET_PAYLOAD(AEXUDP_GET_DATA(buf)),AEXUDP_GET_LEN(buf)-AEXUDP_DATA_GET_PAYLOADINDEX(),dphex,&dlen);
		// log_to_file(hcsdata->log_msgfile,"RECV:{\"c\":%d,\"i\":%d,\"l\":%d,\"d\":%d,\"s\":%d,\"f\":%d,\"m\":\"%s\"}\r\n",
		// 	AEXUDP_GET_CMD(buf),
		// 	AEXUDP_GET_INDEX(buf),
		// 	AEXUDP_GET_LEN(buf),
		// 	AEXUDP_DATA_GET_DST(buf),
		// 	AEXUDP_DATA_GET_SRC(buf),
		// 	hcsdata->hcsdata.last_cmd_from,
		// 	dphex
		// );
		dlen=sizeof(dphex);
		memset(dphex,0, dlen);
		// psus_hint("%s:%d",__func__,__LINE__);
		HexEncode(buf,AEXUDP_GET_PACKET_LEN(buf),dphex,&dlen);
		// psus_hint("%s:%d",__func__,__LINE__);
		if(AEXUDP_GET_LEN(buf)<2){
			//DATA长度小于2字节，说明没有源与目标的域，非法数据包
			psus_hint("GIVEUP AEXUDP:%s\r\n",dphex);
			return 0;
		}else{
			psus_hint("RECV AEXUDP:%s\r\n",dphex);
		}
	}

	psus_hint("dst_addr=%02X,src_addr=%02X,is_gw_broadcast=%02X,loopback=%d,soltmod=%02X",dst_addr,src_addr,is_gw_broadcast(dst_addr),aexudp_is_loopback(buf,len),get_slot_mod(dst_addr));
	if(dst_addr == aexgpio_get_mod_addr() || is_gw_broadcast(dst_addr) || get_slot_mod(dst_addr) == SGW_TYPE_EC){
		if(aexudp_is_loopback(buf,len)){
			psus_hint("Loopback package\r\n");
			return 0;	//环回包，丢弃
		}else{
			//边缘计算需要处理的数据包
			if(is_gw_broadcast(dst_addr) && src_addr == 0){
				//服务器请求了广播包，我们先发给bus通知底层所有模块
				SendtoRS485Bus(hcsdata,dst_addr,AEXUDP_GET_CMD(buf),pdata,plen);
			}
		}
	}else if(dst_addr == SERVERDST_ADDR){
		//目标地址是 0，表示要转发给服务器的数据包
		psus_hint("Dest is server forward to server...");
		SendtoServer(buf,len);
		return len;		//处理结束
	}else if(is_slot_broadcast(dst_addr)){
		//如果是向槽位的广播包，则通过本地发送
		if(src_addr != aexgpio_get_mod_addr()){
			//如果源不是自己则以自己为源发送数据包给目标模块
			psus_hint("broadcast packnet dst=0x%02X\r\n",dst_addr);
			SendtoRS485Bus(hcsdata,dst_addr,AEXUDP_GET_CMD(buf),pdata,plen);
			if(get_slot_mod(dst_addr) != SGW_TYPE_EC){
				//如果是广播包的目标设备类型不是边缘计算类型，则放弃
				psus_hint("broadcast packnet but not ec %02X。",dst_addr);
				return len;
			}
		}else{
			//如果源是自己则丢失包，不做处理
			psus_hint("Giveup\r\n");
			return len;
		}
	}else{
		//如果是边缘计算模块的命令，直接转发给设备模块
		if(src_addr != aexgpio_get_mod_addr()){
			//如果源不是自己则以自己为源发送数据包给目标模块
			psus_hint("Forward to %02X...",dst_addr);
			SendtoRS485Bus(hcsdata,dst_addr,AEXUDP_GET_CMD(buf),pdata,plen);
		}else{
			//如果源是自己则丢失包，不做处理
			psus_hint("Giveup\r\n");
		}
		return len;			//处理结束
	}

	//解析数据包
	switch (AEXUDP_GET_CMD(buf))
	{
		case AEX_CMD_MODBUS:	//Modbus透传指令
			break;
		case AEX_CMD_HEART:		//设备心跳报告
			{
				aexudp_buid_heart_packnet();
				// SendtoServer(buf,AEXUDP_GET_PACKET_LEN(buf));
			}
			break;
		case AEX_CMD_REPORT_EVENT:		//设备事件查询指令
			aexudp_buid_status_packnet(AEX_CMD_REPORT_EVENT);
			break;
		case AEX_CMD_IOSTATUS:	//请求设备IO状态，向服务器报告IO状态，可以作为心跳上报的数据
			if(plen>=1){
				int ioaddr = pdata[0];
				//上报IO状态
				if(ioaddr == 0){
					aexudp_buid_status_packnet(AEX_CMD_IOSTATUS);
				}
			}
			break;
		case AEX_CMD_REPORT_AIN:		//模拟量输入报告，可以分256组，每组8路输入信息，每路输入信息32位(4个字节)
			aexudp_buid_status_packnet(AEX_CMD_AINEVENT);
			break;
		case AEX_CMD_DOSET:	//设置输出状态，可以单设，也可以批量设置，依据掩码实现
			if(plen>=5){
				int ioaddr = pdata[0];
				if(ioaddr == 0){
					unsigned short mask,value,delay=0,delay_s=0;

					value = (pdata[1]<<8) | pdata[2];
					mask = (pdata[3]<<8) | pdata[4];

					if(plen>=7){
						delay = (pdata[5]<<8) | pdata[6];
					}
					if(plen>=9){
						delay_s = (pdata[7]<<8) | pdata[8];
					}
					psus_hint("cmd:%02X,v=%04X,m=%04X,d=%04X",AEX_CMD_DOSET,value,mask,delay);
					if(delay > 0){
						if(fok_for_timer(delay,delay_s) == 0){
							//使用子进程延迟执行
							aexgpio_set_out(mask,value);
							aexudp_buid_status_packnet(AEX_CMD_DOSET);
							exit_for_fok();		//执行完延迟任务退出子进程
						}
					}else{
						//立即执行
						aexgpio_set_out(mask,value);
						aexudp_buid_status_packnet(AEX_CMD_DOSET);
				}
				}
			}
			break;
		case AEX_CMD_DOINVERT:	//设置输出反转，可以单设，也可以批量设置，依据掩码实现
			if(plen>=3){
				int ioaddr = pdata[0];
				if(ioaddr == 0){
					unsigned short mask,delay=0,delay_s=0;

					mask = (pdata[1]<<8) | pdata[2];
					if(plen>=5){
						delay = (pdata[3]<<8) | pdata[4];
					}
					if(plen>=7){
						delay_s = (pdata[5]<<8) | pdata[6];
					}
					//psus_hint("=add:%02x==cmd:%02X,m=%04X,d=%04X===\n", ioaddr, AEX_CMD_OUTINVERT,mask,delay);
					if(delay > 0){
						if(fok_for_timer(delay,delay_s) == 0){
							//使用子进程延迟执行
							unsigned int value = aexgpio_get_out();
							aexgpio_set_out(mask,~value);
							aexudp_buid_status_packnet(AEX_CMD_DOSET);
							exit_for_fok();		//执行完延迟任务退出子进程
						}
					}else{
						//立即执行
						unsigned int value = aexgpio_get_out();
						aexgpio_set_out(mask,~value);	//反转输出
						aexudp_buid_status_packnet(AEX_CMD_DOSET);
					}
				}
			}
			break;
		case AEX_CMD_AOSET:			//模拟量设置输出，可以单设，也可以批量设置，可以设置延时
			break;
		case AEX_CMD_SETTIMER:		//新增定时任务，边缘计算的定时任务使用Linux的crontab来实现。边云测控终端通过从服务器下载shell脚本到机器，然后设置crontab任务来执行此脚本。
			break;
		case AEX_CMD_DELTIMER:		//删除定时任务
			break;
		case AEX_CMD_DIEVENT:		//报告输入变化
			{
				//从命令行获得输入变化的EVENT会发送此命令，从/etc/hotplug.d/aexgpio27/00-changed调用
				// psus_hint("%s:%d",__func__,__LINE__);
				unsigned short v = (pdata[0]<<8)|pdata[1];
				unsigned short ov = (pdata[2]<<8)|pdata[3];

				// aexudp_buid_status_packnet(AEX_CMD_DIEVENT,buf,sizeof(buf));
				#ifdef USE_LUA
					lua_exec(get_psus_data()->lua_fn,v,ov);
				#endif
			}
			break;
		case AEX_CMD_AINEVENT:		//报告模拟输入变化事件
			aexudp_buid_status_packnet(AEX_CMD_AINEVENT);
			break;
		case AEX_CMD_ALERT:			//模块告警
			aexudp_buid_status_packnet(AEX_CMD_ALERT);
			break; 
		case AEX_CMD_DOLUAFUNC:
			if(plen > 3){
				unsigned char p1 = pdata[0];						
				unsigned char p2 = pdata[1];					
				char *luafunc = &pdata[2];	

				pdata[plen-1] = '\0';	//函数名要自带结尾符，如果没有会强制加结尾，否则会导致函数名少一个字符
				#ifdef USE_LUA
					lua_exec_userfunc(get_psus_data()->lua_fn,luafunc,p1,p2);
				#endif
			}
			break;
		case AEX_CMD_TRANSDATA:		//RS232/RS485/CAN/W24(无线)/HART透传数据
			//Data 1字节为设备地址
			//Data 2字节为设备的串口序号，0为底板串口
			psus_hint("plen=%d\n",plen);
			if(plen>1){
				unsigned char uart_index = pdata[0];
				if(uart_index < MAX_UART_NUM){
					//如果命令是给边缘计算的，则将Data去掉前面两个字节的数据发送给对应的串口
					psus_hint("uart_index=%d,uart_fd=%d,type=%d\n",uart_index,hcsdata->hcsdata.uarts[uart_index].uart_fd,hcsdata->hcsdata.uarts[uart_index].type);
					// hcsdata->hcsdata.uarts[uart_index].type == AEX_UART_PACKET_SERVER && 
					if(hcsdata->hcsdata.uarts[uart_index].uart_fd != INVAILDSOCKET){
						#if 1
						pdata[plen] = '\0';
						psus_hint("uart_index=%d,uart_fd=%d,data=%s\n",uart_index,hcsdata->hcsdata.uarts[uart_index].uart_fd,pdata+1);
						#endif
						write(hcsdata->hcsdata.uarts[uart_index].uart_fd,pdata+1,plen-1);
					}
				}
			}
			break;
		case AEX_CMD_MODMSG:
			if(plen>2){
				modbus_pwr((pdata[0]<<8)|pdata[1],pdata[2]);
			}else if(plen>0){
				char hu[100];
				//启用和关闭加热服务
				psus_hint("Heating service used=%d\n",pdata[0]);
				if(hcsdata->Heating_used)
				{
					free(hcsdata->Heating_used);
				}
				sprintf(hu,"%d",pdata[0]);
				hcsdata->Heating_used = strdup(hu);
				sprintf(hu,"uci set kc031srv.@Heating[0].used=%d",pdata[0]);
				system(hu);
				system("uci commit kc031srv");
			}
			break;
		default:
			psus_error("Unknown aexudp command.");
			aexudp_buid_status_packnet(AEXUDP_GET_CMD(buf));
			break;
	}
	return len;
}

static int aexudp_cmd_parse_encrypt(unsigned char *buf,int len)
{
	unsigned char *data = AEXUDP_GET_DATA(buf);
	unsigned char plen = AEXUDP_GET_LEN(buf);
	//解析加密数据包
	unsigned char ddata[255];
	psus_config *hcsdata = get_psus_data();

	memcpy(ddata,0,sizeof(ddata));
	aexudp_sm4_dencrypt(ddata,data,len,hcsdata->hcsdata.ekey);
	memcpy(AEXUDP_GET_DATA(buf),ddata,len);
	return aexudp_cmd_parse(buf,len);
}

int aexudp_recv_from_udp(int udpFd,unsigned char *buf,unsigned int len)
{
	psus_config *psudata = get_psus_data();
	struct sockaddr_in addr;
	size_t addr_len = sizeof(struct sockaddr);
	memset(buf, 0, sizeof(buf));
	memset(&addr, 0, sizeof(struct sockaddr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(0);

	// psus_hint("%s:%d",__func__,__LINE__);
	len = recvfrom(udpFd, buf, len, 0, (struct sockaddr *)&addr, &addr_len);
	// psus_hint("%s:%d",__func__,__LINE__);
	if (len > 0)
	{
#ifdef PSU_DEBUG
		// psus_hint("buf[6]=%02x",buf[6]);
		psus_hint("UDP From 0x%08X %s:%d [%d]:",addr.sin_addr.s_addr,IP2Str(addr.sin_addr.s_addr), ntohs(addr.sin_port), len);
		dump_buffer("",buf, len);
#endif
		// psus_hint("buf[6]=%02x",buf[6]);
		if (addr.sin_addr.s_addr != 0x0100007F)
		{
			psudata->hcsdata.last_cmd_from = AEX_LCF_UDP; // 不是从本机发送的命令
		}else{
			psudata->hcsdata.last_cmd_from = AEX_LCF_ME;
		}
		// if ((addr.sin_addr.s_addr != 0x0100007F && (psudata->hcsdata.tcp_addr.sin_addr.s_addr != addr.sin_addr.s_addr)))
		// {
		// 	psudata->hcsdata.tcp_addr.sin_addr.s_addr = addr.sin_addr.s_addr;
		// 	CloseTcpSocket(psudata);
		// 	StartTcpSocket(psudata);
		// }
	}
	return len;

}

#endif  //USE_AEX_UDPs

